import React from 'react';
// 枚举------------------------
enum enumType {
  start, // 0
  stop, // 1
  end, // 2
  other = 5,
}

// type nn = 'a' | 'b'
// type mm = 'c' | 'c'
// type ll = `${nn}-${mm}`

// 泛型 ------------------------
type name<T> = {
  value: T;
  name?: name<T>; // type使用自己
  obj: { [key: string]: string }; // 对象表达式
};
interface TsTestProps<T, U> {
  // 接口
  // T为定义的泛型可以是各种类型,可以传入多个通过","分开(相当于ts的传参)
  title?: T;
  age?: U;
  obj?: name<string>;
}
function Fn<T>(arg: T): T {
  // 第一个T代表当前函数中存在泛型T,第二个T代表传入的参数类型,第三个T代表函数最终的返回类型
  let str: T;
  return arg;
}

// 类型合并------------------------
type typeName = Common & TsTestProps<string, number>; // 类型别名

interface extendInterface extends typeName, Interface {
  // interface继承
  P: string;
}

interface extendInterface extends TsTestProps<string, number>, Interface {
  // interface继承
  P: string;
}

let n: extendInterface = {
  P: '1',
};

// 对比type和interface------------------
type Alias = { name?: string };
// type Alias = { age: number }; // 不能同名
interface Interface {
  num?: number;
}
interface Interface {
  // 可以同名并且自动合并
  age?: number;
}
// 鼠标悬停的提示也不同type能显示具体的信息
// implements用来定义class的数据类型
class A implements Alias {
  name?: string;
  constructor(name?: string) {
    this.name = name ?? '名称';
  }
}
// class的extends继承要在ts的implements之前
class B extends A implements Interface {
  num!: number; // !:强制解析表示肯定有值,并排除null和undefined
  age?: number;
  name!: string;
  constructor(num: number, age?: number, name?: string) {
    super(name);
    this.num = num ?? 10;
    this.age = age ?? 10;
  }
}
new B(20);

// keyof枚举出ts接口中的键名称-------------
interface typeKeyof {
  name: string;
  age: number;
}
type Person = keyof typeKeyof; // 'name' | 'age' keyof获取对象的属性名
const nm: Person = 'age';

// ts的extends继承---------------------
function extendsFn<T, K extends keyof T>(obj: T, arr: Array<K>): void {
  // <T, K extends keyof T>代表extendsFn函数中存在泛型T和K泛型(K为T泛型对象中的键名称)
  // 开发框架或封装通用组件可能会用到
}
extendsFn({ name: '123445', age: 23456 }, ['age', 'name']);

// ts类型映射用于映射ts定义的类型-------------------
type extendT<T, U extends keyof T> = {
  [P in U]: T[P]; // T[P]取到ts定义的泛型T的对应的键类型
  // [P in U]?: T[P] // 将参数变为可选
  // [P in U]?: string // 将类型改变为string
};
// type Partial<T> = {
//   [P in keyof T]?: T[P];
// };
const g: Partial<{ name: string; age: number }> = {
  age: 134,
  name: '2345',
};
const h: extendT<{ name: string; age: number }, 'age' | 'name'> = {
  age: 134,
  name: '234',
};
function aa<T extends extendT<T, K>, K extends keyof T>(
  obj: T,
  arg: K
): { a: T } {
  return {
    a: obj,
  };
}
aa({ name: 1231 }, 'name');
function bb<T extends Partial<T>>(obj: T): { a: T } {
  return {
    a: obj,
  };
}
bb({ name: 1234 });
type Keys = 'option1' | 'option2';
type Flags = { [K in Keys]?: boolean };
const l: Flags = {
  option1: false,
  option2: true,
};

// namespace
let testNamespace: test = {
  b: {
    a: '123123',
  },
};

function a(): never {
  // never 没有返回类型如死循环或者抛出错误
  console.log(111);
  throw new Error('');
}

type pick = Pick<extendInterface, 'age'>; // 只使用extendInterface的age属性

type omit = Omit<extendInterface, 'age'>; // 不使用extendInterface的age属性

type extract = Extract<'a' | 'b' | 'c', 'a' | 'f'>; // 匹配出a和f

type exclude = Exclude<'a' | 'b' | 'c', 'a'>; // 匹配出a以外的属性

type RecordTest = Record<string, any>; // 定义对象中的各项属性为any

let hh: RecordTest = { 1: '' };

type partial = Partial<pick>; // 罗列出pick类型变为非必选

const TsTest = ({
  title,
  age,
  obj = {
    value: 'string',
    obj: { name: 'a' },
  },
}: TsTestProps<string, number> & Common): JSX.Element => {
  return <div></div>;
};

export default TsTest;
